/**
 * MP Software.
 */
package controllers;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import models.Client;
import models.Deduction;
import models.Employee;
import models.Payment;
import models.Payroll;
import models.PayrollPeriod;
import play.mvc.Controller;
import service.CalculationResult;
import service.PaymentDeductionFacade;
import service.PayrollRegisterResult;
import service.PayrollRegisterService;
import controllers.views.DeductionTypeView;
import controllers.views.PaymentTypeView;

/**
 * @author Jeremiah John M. Macariola
 *
 */
public class PayrollRegister extends Controller {

    @Inject
    private static PayrollRegisterService payrollRegisterService;

    @Inject
    private static PaymentDeductionFacade paymentDeductionFacade;

    public static void index(Long payrollPeriodId) {
        Client client = loadClient();
        List<Employee> employees = loadEmployees(client);
        PayrollPeriod payrollPeriod = PayrollPeriod.findById(payrollPeriodId);

        String electronicId = client.electronicId;
        PayrollRegisterResult result = payrollRegisterService.process(
                electronicId, payrollPeriod);
        Map<Long, Payroll> employeePayrolls = result.getEmployeePayrolls();
        Map<String, Float> employeePayments = result.getEmployeePayments();
        Map<String, BigDecimal> employeeDeductions = result
                .getEmployeeDeductions();
        Map<Long, CalculationResult> calculationResults = result
                .getCalculationResults();

        List<PaymentTypeView> paymentTypes = paymentDeductionFacade
                .getPaymentTypes(electronicId);
        List<DeductionTypeView> deductionTypes = paymentDeductionFacade
                .getDeductionTypes(electronicId);

        session.put("payrollPeriodId", payrollPeriod.id);

        render(payrollPeriod, employees, employeePayrolls, employeePayments,
                employeeDeductions, calculationResults, paymentTypes,
                deductionTypes);
    }

    private static List<Employee> loadEmployees(Client client) {
        List<Employee> employees = Employee.find(
                "client = ? order by name asc", client).fetch();
        return employees;
    }

    private static Client loadClient() {
        Long clientId = Long.valueOf(session.get("clientId"));
        Client client = Client.findById(clientId);
        return client;
    }

    public static void findPayroll(Long employeeId, Long payrollPeriodId,
            Long payrollId) {
        Employee employee = Employee.findById(employeeId);
        PayrollPeriod payrollPeriod = PayrollPeriod.findById(payrollPeriodId);

        Payroll payroll = new Payroll(employee, payrollPeriod);
        Map<String, Float> payrollPayments = new HashMap<String, Float>();
        Map<String, BigDecimal> payrollDeductions = new HashMap<String, BigDecimal>();

        if (payrollId != null) {
            payroll = Payroll.findById(payrollId);

            List<Payment> payments = Payment.find("byPayroll", payroll).fetch();
            for (Payment payment : payments) {
                payrollPayments.put(payment.paymentType, payment.hours);
            }

            List<Deduction> deductions = Deduction.find("byPayroll", payroll)
                    .fetch();
            for (Deduction deduction : deductions) {
                payrollDeductions.put(deduction.deductionType, deduction.value);
            }
        }

        String electronicId = employee.client.electronicId;
        List<PaymentTypeView> paymentTypes = paymentDeductionFacade
                .getPaymentTypes(electronicId);
        List<DeductionTypeView> deductionTypes = paymentDeductionFacade
                .getDeductionTypes(electronicId);

        render(payroll, payrollPayments, payrollDeductions, employee,
                payrollPeriod, paymentTypes, deductionTypes);
    }

    public static void savePayroll(Long employeeId, Long payrollPeriodId,
            Long payrollId) {
        Employee employee = Employee.findById(employeeId);
        String electronicId = employee.client.electronicId;
        Payroll payroll = null;

        Map<String, String> paymentDeductionParams = params.allSimple();

        /*
         * Get or create payroll instance.
         */
        boolean hasValue = paymentDeductionFacade.hasValue(electronicId,
                paymentDeductionParams);
        if (payrollId != null) {
            payroll = Payroll.findById(payrollId);

            /*
             * Delete payroll for this employee if no value at all.
             */
            if (!hasValue) {
                deletePayroll(payroll);
            }

        } else if (hasValue) {
            PayrollPeriod payrollPeriod = PayrollPeriod.findById(payrollPeriodId);
            payroll = Payroll.find("byEmployeeAndPayrollPeriod", employee, payrollPeriod).first();

            if (payroll == null) {
                payroll = new Payroll(employee, payrollPeriod);
                payroll.save();
            }
        }

        paymentDeductionFacade.savePayments(electronicId, payroll,
                paymentDeductionParams);
        paymentDeductionFacade.saveDeductions(electronicId, payroll,
                paymentDeductionParams);

        index(payrollPeriodId);
    }

    private static void deletePayroll(Payroll payroll) {
        List<Payment> payments = Payment.find("byPayroll", payroll).fetch();
        for (Payment payment : payments) {
            payment.delete();
        }

        List<Deduction> deductions = Deduction.find("byPayroll", payroll)
                .fetch();
        for (Deduction deduction : deductions) {
            deduction.delete();
        }

        payroll.delete();
    }

}
